package com.warren.system.service.impl;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import com.warren.system.entity.File;
import com.warren.system.entity.OssEntity;
import com.warren.system.service.AliOssService;
import org.joda.time.DateTime;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;
import java.util.UUID;

/**
 * @author warren
 * @date 2021/3/23 0023 15:15
 * @Description
 * 在创建这个类的时候就一个把属性装载好
 **/
@Service
public class AliOssServiceImpl implements AliOssService , InitializingBean {

    @Autowired
    private OssEntity ossEntity;

    private String endpoint;
    private String accessKeyId;
    private String accessKeySecret;
    private String bucketName;

    /**
     * 初始化bean之后需要进行的操作
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        endpoint = ossEntity.getEndpoint();
        accessKeyId = ossEntity.getAccesskeyId();
        accessKeySecret = ossEntity.getAccessKeySecret();
        bucketName = ossEntity.getBucketName();
    }

    @Override
    public void createBucket() {
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        if (ossClient.doesBucketExist(bucketName)){
            throw new RuntimeException(bucketName + "在对象存储的Bucket表中已经存在");
        }

        // 创建存储空间。
        ossClient.createBucket(bucketName);

        // 关闭OSSClient。
        ossClient.shutdown();
    }

    @Override
    public File upload(MultipartFile file) {
        File file2 = new File();
        //上传的地址
        String uploadUrl = null;

        OSS ossClient = null;
        try {
            // 创建OSSClient实例。
            ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

            if (!ossClient.doesBucketExist(bucketName)){
                ossClient.createBucket(bucketName);
                ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);
            }
            //获取上传的文件流
            InputStream inputStream = file.getInputStream();

            //构建日期的文件路径 avatar/2020/10/10/文件名
            String datePath = new DateTime().toString("yyyy/MM/dd");
            //获取上传文件的全名称
            String original = file.getOriginalFilename();
            //获取UUID
            String filename = UUID.randomUUID().toString().replaceAll("-", "");
            //获取上传文件的扩展名
            String fileType = original.substring(original.lastIndexOf("."));

            //拼接文件名称
            String newName = filename + fileType;

            //生成文件夹
            filename = datePath+"/"+newName ;

            //文件属性
            file2.setFileName(newName);
            file2.setSize(file.getSize());
            file2.setType(fileType);

            //实现图片预览的效果，要设置以下几点
            //1.设置文件的ACL权限 要么是公共读，要么公共读写
            //2.设置文本类型(image/jpg)
            ObjectMetadata objectMetadata = new ObjectMetadata();
            //设置公共读权限
            objectMetadata.setObjectAcl(CannedAccessControlList.PublicRead);
            // 设置类型
            objectMetadata.setContentType(getContentType(fileType));

            //每次上传得到的名字肯定是不能相同的，在java中如何让每次生成的名字不一样？
            //uuid redis 分布式id 雪花算法 为了更加方便的区分，文件格式yyyy/MM/dd+uuid

            //上传
            ossClient.putObject(bucketName,filename,inputStream,objectMetadata);

            // 关闭OSSClient。
            ossClient.shutdown();

            //默认10年不过期
            Date expiration = new Date(System.currentTimeMillis() + 1600L * 1000 * 24 * 365 * 10);

            //bucket名称 文件名 过期时间
            uploadUrl = ossClient.generatePresignedUrl(bucketName,filename,expiration).toString();

        } catch (Exception e) {
            e.printStackTrace();
        }
        file2.setUrl(uploadUrl.substring(0,uploadUrl.indexOf("?")));

        return file2;
    }

    @Override
    public void download(String fileName) throws IOException {
        // <yourObjectName>从OSS下载文件时需要指定包含文件后缀在内的完整路径，例如abc/efg/123.jpg。
        String objectName = fileName;

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // 调用ossClient.getObject返回一个OSSObject实例，该实例包含文件内容及文件元信息。
        OSSObject ossObject = ossClient.getObject(bucketName, objectName);
        // 调用ossObject.getObjectContent获取文件输入流，可读取此输入流获取其内容。
        InputStream content = ossObject.getObjectContent();
        if (content != null) {
            try {
                BufferedReader reader = new BufferedReader(new InputStreamReader(content));
                while (true) {
                    String line = reader.readLine();
                    if (line == null) {
                        break;
                    }
                    System.out.println("\n" + line);
                }
                // 数据读取完成后，获取的流必须关闭，否则会造成连接泄漏，导致请求无连接可用，程序无法正常工作。
                content.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        // 关闭OSSClient。
        ossClient.shutdown();
    }

    @Override
    public void  downLoadFile(HttpServletResponse response,String fileName){
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        OSSObject ossObject = ossClient.getObject(new GetObjectRequest(bucketName, fileName));

        if (ossObject != null){
            InputStream inputStream = ossObject.getObjectContent();
            int buffer = 1024 * 10;
            byte[] data = new byte[buffer];

            try {
                int read;
                while ((read = inputStream.read(data)) != -1){
                    response.getOutputStream().write(data,0,read);
                }
                response.getOutputStream().flush();
                response.getOutputStream().close();
                ossObject.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        ossClient.shutdown();
    }

    @Override
    public void listFile() {
        try {
            // 创建OSSClient实例。
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

            // ossClient.listObjects返回ObjectListing实例，包含此次listObject请求的返回结果。
            ObjectListing objectListing = ossClient.listObjects(bucketName);
            // objectListing.getObjectSummaries获取所有文件的描述信息。
            for (OSSObjectSummary objectSummary : objectListing.getObjectSummaries()) {
                System.out.println(" - " + objectSummary.getKey() + "  " +
                        "(size = " + objectSummary.getSize() + ")");
            }

            // 关闭OSSClient。
            ossClient.shutdown();
        } catch (OSSException e) {
            e.printStackTrace();
        } catch (ClientException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void deleteFile(String fileName) {
        try {
            // <yourObjectName>从OSS下载文件时需要指定包含文件后缀在内的完整路径，例如abc/efg/123.jpg。
            String objectName = fileName;

            // 创建OSSClient实例。
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

            // 删除文件。
            ossClient.deleteObject(bucketName, objectName);

            // 关闭OSSClient。
            ossClient.shutdown();
        } catch (OSSException e) {
            e.printStackTrace();
        } catch (ClientException e) {
            e.printStackTrace();
        }
    }

    /**
     * Description: 判断OSS服务文件上传时文件的contentType
     *
     * @param FilenameExtension 文件后缀
     * @return String
     */
    public static String getContentType(String FilenameExtension) {
        if (FilenameExtension.equalsIgnoreCase(".bmp")) {
            return "image/bmp";
        }
        if (FilenameExtension.equalsIgnoreCase(".gif")) {
            return "image/gif";
        }
        if (FilenameExtension.equalsIgnoreCase(".jpeg") ||
                FilenameExtension.equalsIgnoreCase(".jpg") ||
                FilenameExtension.equalsIgnoreCase(".png")) {
            return "image/jpg";
        }
        if (FilenameExtension.equalsIgnoreCase(".html")) {
            return "text/html";
        }
        if (FilenameExtension.equalsIgnoreCase(".txt")) {
            return "text/plain";
        }
        if (FilenameExtension.equalsIgnoreCase(".vsd")) {
            return "application/vnd.visio";
        }
        if (FilenameExtension.equalsIgnoreCase(".pptx") ||
                FilenameExtension.equalsIgnoreCase(".ppt")) {
            return "application/vnd.ms-powerpoint";
        }
        if (FilenameExtension.equalsIgnoreCase(".docx") ||
                FilenameExtension.equalsIgnoreCase(".doc")) {
            return "application/msword";
        }
        if (FilenameExtension.equalsIgnoreCase(".xml")) {
            return "text/xml";
        }
        return "image/jpg";
    }

}
